package org.lboot.flow.controller;

import cn.hutool.core.lang.Validator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.lboot.core.auth.AuthService;
import org.lboot.core.domain.ResponseDTO;
import org.lboot.core.exception.BusinessException;
import org.lboot.flow.FlowCtl;
import org.lboot.flow.module.assign.FlowTaskAssign;
import org.lboot.flow.module.assign.FlowTaskAssignService;
import org.lboot.flow.module.work.FlowWork;
import org.lboot.flow.module.work.FlowWorkService;
import org.lboot.flow.module.work.params.FlowTaskParams;
import org.lboot.flow.params.FlowTaskQueryParams;
import org.lboot.jpa.utils.JpaDataUtil;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

/**
 * @author kindear
 */
@Slf4j
@RestController
@RequestMapping("flow")
@Api(tags = "流程任务管理")
@AllArgsConstructor
public class FlowTaskController {
    // 鉴权服务
    AuthService authService;

    // 流程任务分配服务
    FlowTaskAssignService taskAssignService;

    // 流程任务服务
    FlowWorkService flowWorkService;

    FlowCtl flowCtl;

    /**
     * 查询结果可以通过 TaskResultHandle 处理
     * @param params
     * @return 待审核任务列表
     */
    @GetMapping("tasks")
    @ApiOperation(value = "流程任务查询")
    public ResponseDTO<Object> taskQueryList(FlowTaskQueryParams params){
        Pageable pageable = JpaDataUtil.buildPageable(params);

        // 获取当前登录用户全部任务分配
        List<FlowTaskAssign> assigns = taskAssignService.getUserAssigns();
        // 组合查询
        Specification<FlowWork> workSpec = (root, query, cb) -> {
            List<Predicate> list = new ArrayList<>();
            for (FlowTaskAssign assign:assigns){
                Predicate p = cb.and(
                        cb.equal(root.get("flowCode").as(String.class), assign.getFlowCode()),
                        cb.equal(root.get("currentNodeId").as(String.class),assign.getFlowNodeId())
                );
                list.add(p);
            }
            Predicate[] predicates = new Predicate[list.size()];
            List<Predicate> uniQuery = new ArrayList<>();
            // 加入OR查询
            uniQuery.add(cb.or(list.toArray(predicates)));
            // 流程实例装填
            if (Validator.isNotEmpty(params.getFlowWorkStatus())){
                uniQuery.add( cb.equal(root.get("flowWorkStatus").as(String.class), params.getFlowWorkStatus()));
            }
            // 是否挂起
            if (Validator.isNotEmpty(params.getStatus())){
                uniQuery.add(cb.equal(root.get("status").as(Integer.class), params.getStatus()));
            }
            // 发起人信息
            if (Validator.isNotEmpty(params.getInitiator())){
                uniQuery.add(cb.equal(root.get("initiator").as(String.class), params.getInitiator()));
            }
            Predicate[] uniPredicates = new Predicate[uniQuery.size()];
            return cb.and(uniQuery.toArray(uniPredicates));
        };
        return ResponseDTO.succData(
                flowWorkService.getAll(pageable,workSpec)
        );
    }


    @PostMapping("tasks/complete")
    @ApiOperation(value = "流程任务通过")
    public ResponseDTO<Object> completeTask(@Validated @RequestBody FlowTaskParams taskParams){
        flowCtl.completeTask(taskParams);
        // 获取流程实例ID
        String flowWorkId = taskParams.getFlowWorkId();
        FlowWork flowWork = flowWorkService.getOneUnwrap(flowWorkId);
        return ResponseDTO.succData(flowWork);
    }


    @PostMapping("tasks/reject")
    @ApiOperation(value = "流程任务驳回")
    public ResponseDTO<Object> rejectTask(@Validated @RequestBody FlowTaskParams taskParams){
        if (Validator.isEmpty(taskParams.getRemark())){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"驳回意见不可为空");
        }
        flowCtl.rejectTask(taskParams);
        // 获取流程实例ID
        String flowWorkId = taskParams.getFlowWorkId();
        FlowWork flowWork = flowWorkService.getOneUnwrap(flowWorkId);
        return ResponseDTO.succData(flowWork);
    }
}
